#include "QFfplayer.h"
#include <QDebug>

enum {
    STATE_ERROR=-1,
    STATE_STOP=0,
    STATE_RUN,
    STATE_PAUSE,
};

extern "C" {
    extern int seek_by_bytes;
    extern int show_loop;

    /*  退出播放线程    */
    extern int do_exit(VideoState *is);
    /*  调整播放框大小  */
    //extern void fill_rectangle(int x, int y, int w, int h);
    /*  获取播放时间？  */
    extern double get_clock(Clock *c);
    /*  设置播放时间？  */
    extern void set_clock(Clock *c, double pts, int serial);
    /*  设置播放速度    */
    extern double set_clock_speed(Clock *c, double speed);

    extern double get_master_clock(VideoState *is);
    /*  快进操作    */
    extern void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes);
    extern int stream_seek_safe(VideoState *cur_stream, double incr, int seek_by_bytes);

    /*  视频启停操作    */
    extern void stream_toggle_pause(VideoState *is);
    extern int toggle_pause(VideoState *is);
    /*  静音启停操作    */
    extern int toggle_mute(VideoState *is);
    /*  调节音量    */
    extern int update_volume(VideoState *is, int sign, double step);
    /*  ?   */
    extern double get_rotation(AVStream *st);
    /*  音频启停操作    */
    extern void toggle_audio_display(VideoState *is);
    /*  改变显示操作    */
    extern int change_show_mode(VideoState *is);
}

void PlayerThread::run() {
    int ret;
    emit playStart(1);
    ret = ffwrap_main(video_state, show_file_name.toStdString().c_str());
    emit playStop(ret);
}

void PlayerThread::setVideoState(VideoState *is)
{
    video_state = is;
}

QFfplayer::QFfplayer(QObject *parent) : QObject(parent)
{
    m_pVideoState = NULL;
    m_showFileName = QString("");
    m_pauseState = 0;
    m_currentState = STATE_STOP;
    m_pPlayThd = new PlayerThread();
    m_render_wnd = NULL;

    /*
    *   When the play thread stop or start, we need to get it and change 
    *   the state message.
    */
    connect(m_pPlayThd, &PlayerThread::playStop, this, &QFfplayer::updateState);
    connect(m_pPlayThd, &PlayerThread::playStart, this, &QFfplayer::updateState);
}

QFfplayer::~QFfplayer()
{
    stopVideo();
}

/* 
*   Set the Qt window id. 
*   This window id will be used in the external module.
*   It is used the create a SDL window into the Qt window.
*/
void QFfplayer::setWinID(void *winID)
{
    m_render_wnd = winID;
    if (NULL != m_pVideoState) {
        m_pVideoState->winId = winID;
    }
}

/* Set the display file name. */
void QFfplayer::setDisplayFile(const QString& filename)
{
    m_showFileName = filename;
}

/* compeleted. */
void myImageCleanupHandler(void *info) {
    qDebug() <<  "QImage cleanup with:" << info;
    void * ptr = info;
    av_freep(&ptr);
}
/* Get the current image which is display. */
const QImage& QFfplayer::getCurrentImage()
{
    if (m_pVideoState && STATE_RUN == m_currentState) {
        AVFrame frame;
        int ret = ffwrap_snapshot(m_pVideoState, &frame);
        if (!ret) {
            QImage image(frame.data[0], frame.width, frame.height,
                         frame.linesize[0], QImage::Format_RGB888,
                         myImageCleanupHandler, frame.data[0]);
            m_currentImage = image;
            //av_freep(&(frame.data[0]));
            qDebug() << "get image succ";
        } else {
            qWarning() << "get rgb data fail";
        }
    }
    return m_currentImage;
}

int QFfplayer::playVideo(const QString& filename)
{
    if ((filename.size() == 0) || (m_currentState != STATE_STOP)) {
        qDebug() << "invalid input file or state:" << m_currentState;
        return -1;
    }

    if (m_pVideoState) {
        ffwrap_destroy_videostate(m_pVideoState);
        m_pVideoState = NULL;
    }
    if (NULL == m_pVideoState) {
        m_pVideoState = ffwrap_create_videostate();
        qInfo() << "create video state:" << m_pVideoState << m_render_wnd;
        if (NULL == m_pVideoState) {
            qWarning() << "malloc video state fail";
            return -2;
        }
    }
    m_currentState = STATE_RUN;
    m_showFileName = filename;
    m_pPlayThd->setDisplayFile(m_showFileName);
    m_pPlayThd->setVideoState(m_pVideoState);
    m_pVideoState->winId = m_render_wnd;
    
    /*  
    *   We will call the play function in the another thread.
    *   Because the play function will be blocked.
    */
    m_pPlayThd->start();    
    
    return 0;
}

/* compeleted. */
int QFfplayer::stopVideo()
{
    int ret = -1;
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        m_pVideoState->exit_flag = 1;
        qDebug() << "stopVideo after set exit_flag";
        m_pPlayThd->wait();
        qDebug() << "stopVideo after main_loop thread exit";
        ret = do_exit(m_pVideoState);
        qDebug() << "stopVideo after do_exit " << ret;

        m_currentState = STATE_STOP;
    }
    qDebug()<< "after stop video:" << m_currentState;
    //m_pPlayThd->terminate();
    return ret;
}

/* compeleted. */
int QFfplayer::pauseVideo()
{
    if (m_pVideoState && (m_currentState > STATE_STOP)/* && m_pauseState*/) {
        m_pauseState = toggle_pause(m_pVideoState);
        return m_pauseState;
    }
    return -1;
}

/* don't use. */
int QFfplayer::resumeVideo()
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        return m_pauseState = toggle_pause(m_pVideoState);
    }
    return -1;
}

/* compeleted. */
int QFfplayer::updateVolume(int sign, double step)
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        return update_volume(m_pVideoState, sign, step);
    }
    return -1;
}

/* compeleted. */
int QFfplayer::muteAudio()
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        return ::toggle_mute(m_pVideoState);
    }
    return -1;
}

/* compeleted. */
int QFfplayer::changeShowMode()
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        return change_show_mode(m_pVideoState);
    }
    return -1;
}

/* comeleted. */
int QFfplayer::setSubtitleFile(const QString &filename)
{
    m_subtitileFileName = filename;
}

/*  compeleted  */
/* Update the speed of playing video. */
double QFfplayer::updateSpeed(double val, int relative)
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        if (relative) {
            set_clock_speed(&(m_pVideoState)->extclk, (m_pVideoState)->extclk.speed + val);
        } else {
            set_clock_speed(&(m_pVideoState)->extclk, val);
        }
        return (m_pVideoState)->extclk.speed;
    }
    return -1;
}

/* compeleted. */
/* Seek the playing position of the video. */
int QFfplayer::stream_seek_safe(double incr, int seek_by_bytes)
{
    if (m_pVideoState && (m_currentState != STATE_STOP)) {
        return ::stream_seek_safe(m_pVideoState, incr, seek_by_bytes);
    }
    return -1;
}


